package org.jsola.hr.task;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IAttendPlanDAO;
import org.jsola.hr.dao.IAttendPunchDailyReportDAO;
import org.jsola.hr.dao.IAttendPunchDailySummaryDAO;
import org.jsola.hr.dao.IAttendPunchRecordDAO;
import org.jsola.hr.entity.*;
import org.jsola.hr.query.AttendPunchDeptQuery;
import org.jsola.hr.query.AttendPunchStaffQuery;
import org.jsola.hr.query.EmpDepQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.StaffVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;


/**
 * 考勤打卡日统计
 *
 * 考勤打卡日汇总 - hr_attend_punch_daily_summary
 * 考勤打卡日报表 - h_attend_punch_daily_report
 *
 * @author wxz
 */
@Component
@Slf4j
public class AttendPunchDailySummaryTask {

    @Autowired
    private IAttendPunchDailySummaryDAO attendPunchDailySummaryDAO;
    @Autowired
    private IAttendPlanDAO attendPlanDAO;
    @Autowired
    private IAttendPunchStaffService attendPunchStaffService;
    @Autowired
    private IAttendPunchDeptService attendPunchDeptService;
    @Autowired
    private IEmpDepService empDepService;
    @Autowired
    private IAttendPunchDailyReportDAO attendPunchDailyReportDAO;
    @Autowired
    private IEmpInfoService empInfoService;
    @Autowired
    private IAttendPunchRecordDAO attendPunchRecordDAO;
    @Autowired
    private IAttendPunchTimeService attendPunchTimeService;
    @Autowired
    private IAttendCalendarService attendCalendarService;
    @Autowired
    private IDepInfoService depInfoService;

    /**
     * 初始化考勤打卡日统计
     *
     * @throws ParseException
     */
    //@Scheduled(cron = "0 */1 * * * ?") // 每5秒执行/
    @Scheduled(cron = "30 10 1 * * ?") // 每天1点10分30秒触发
    // @Scheduled(cron = "01 00 17 * * ?") // 每天1点20分30秒触发
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void createDailySummary() throws ParseException {

        log.info("开始 ---> 初始化考勤打卡日统计");

        String yearly = DateFormatUtils.format(new Date(), "yyyy");
        String monthly = DateFormatUtils.format(new Date(), "MM");
        String daily = DateFormatUtils.format(new Date(), "dd");
        String dateStr = DateFormatUtils.format(new Date(), "yyyy-MM-dd");

        // 查询所有的考勤规则
        Example example = new Example(AttendPlanDO.class);
        example.and()
                .andEqualTo("valid", true);
        List<AttendPlanDO> attendPlanList = attendPlanDAO.selectByExample(example);
        if (attendPlanList.size() <= 0) {
            return;
        }

        // 考勤打卡参与人员
        for (AttendPlanDO plan : attendPlanList) {

            Set<StaffVO> staffIds = new HashSet<StaffVO>();

            // 查询考勤打卡参与人员
            Set<StaffVO> set1 = this.getStaffSetForPunchStaff(plan.getId(), plan.getSiteId());
            if (set1.size() > 0) {
                for (StaffVO staffVO : set1) {
                    staffIds.add(staffVO);
                }
            }

            // 查询考勤打卡参与部门
            Set<StaffVO> set2 = this.getStaffSetForPunchDep(plan.getId(), plan.getSiteId());
            if (set2.size() > 0) {
                for (StaffVO staffVO : set2) {
                    staffIds.add(staffVO);
                }
            }

            // 初始化考勤打卡日汇总
            AttendPunchDailySummaryDO dailySummary = this.getAttendPunchDailySummaryDO(plan, staffIds);
            attendPunchDailySummaryDAO.insert(dailySummary);

            // 初始化考勤打卡日报表
            if (staffIds.size() > 0) {

                for (StaffVO staffVO : staffIds) {

                    AttendPunchDailyReportDO dailyReport = this.getAttendPunchDailyReport(dailySummary.getId(), plan, staffVO);
                    attendPunchDailyReportDAO.insert(dailyReport);

                } // 初始化每个人
            }
        } // 结束规则循环
    }

    /**
     * 初始化打卡记录
     *
     * @param punchType 打卡类型 ; 0-无效打卡,1-上班打卡,2-下班打卡
     * @param standardTime 上班或下班时间
     * @param plan 考勤规则
     * @param staffVO 考勤人员
     * @return 考勤记录
     */
    private AttendPunchRecordDO initAttendPunchRecord(Integer punchType, String standardTime, AttendPlanDO plan, StaffVO staffVO) {

        String yearly = DateFormatUtils.format(new Date(), "yyyy");
        String monthly = DateFormatUtils.format(new Date(), "MM");
        String daily = DateFormatUtils.format(new Date(), "dd");

        // 查询员工所在部门
        DepInfoDO depInfo = this.getDepInfo(staffVO.getEmpInfoId(), plan.getSiteId());

        // 打卡记录
        AttendPunchRecordDO onWorkRecord = new AttendPunchRecordDO();

        onWorkRecord.setId(UUID.randomUUID().toString().replace("-", ""));
        // 公司ID
        onWorkRecord.setCompanyId(plan.getCompanyId());
        // 公司名称
        onWorkRecord.setCompanyName(plan.getCompanyName());
        // 部门ID
        onWorkRecord.setDeptId(depInfo != null ? depInfo.getId() : "");
        // 部门名称
        onWorkRecord.setDeptName(depInfo != null ? depInfo.getName() : "");
        // 员工ID
        onWorkRecord.setEmpInfoId(staffVO.getEmpInfoId());
        // 员工姓名
        onWorkRecord.setEmpInfoName(staffVO.getEmpInfoName());
        // 考勤方案
        onWorkRecord.setAttendPlanId(plan.getId());
        // 考勤方案名称
        onWorkRecord.setAttendPlanName(plan.getName());
        // 年度
        onWorkRecord.setYear(yearly);
        // 月
        onWorkRecord.setMonth(monthly);
        // 日
        onWorkRecord.setDay(daily);
        // 打卡类型 ; 0-无效打卡,1-上班打卡,2-下班打卡
        onWorkRecord.setPunchType(punchType);
        // 标准时间
//        onWorkRecord.setStandardTime(standardTime);
        // 打卡时间(HH:mm)
        onWorkRecord.setPunchTime(null);
        // 打卡状态 ; 0-无效打卡,1-正常,2-迟到,3-早退
        onWorkRecord.setPunchStatus(0);
        // 迟到/早退分钟数
        onWorkRecord.setMinute(0);
        // 判定描述
        onWorkRecord.setDecisionDesc("");
        // 打卡坐标
        onWorkRecord.setCoordinate("");
        // 打卡地点
        onWorkRecord.setLocation("");
        // 打卡wifi
        onWorkRecord.setPunchWifi("");
        // 打卡来源 ; 1-app打卡,2-考勤机打卡
        onWorkRecord.setPunchSource(1);
        // 是否补卡 ; 1-是,0-否
        onWorkRecord.setIsMakeUp(false);
        onWorkRecord.setCreateUserId("");
        onWorkRecord.setGmtCreate(new Date());
        onWorkRecord.setModifiedUserId("");
        onWorkRecord.setGmtModified(new Date());
        onWorkRecord.setSiteId(plan.getSiteId());
        onWorkRecord.setValid(true);

        return onWorkRecord;
    }

    /**
     *
     * @param empInfoId
     * @param siteId
     * @return
     */
    private DepInfoDO getDepInfo(String empInfoId, String siteId) {

        DepInfoDO depInfoDO = null;

        EmpDepQuery empDepQuery = new EmpDepQuery();
        empDepQuery.setEmpId(empInfoId);
        List<EmpDepDO> empDepList = empDepService.selectDO(empDepQuery, siteId);
        if (empDepList.size() <= 0) {
            return depInfoDO;
        }

        // 查询部门信息
        depInfoDO = depInfoService.selectDOById(empDepList.get(0).getDepId(), siteId);

        return depInfoDO;
    }

    /**
     * 获取打卡记录
     *
     * @param plan
     * @param staffVO
     * @return
     */
    private AttendPunchRecordDO getAttendPunchRecord(AttendPlanDO plan, StaffVO staffVO) {

        String yearly = DateFormatUtils.format(new Date(), "yyyy");
        String monthly = DateFormatUtils.format(new Date(), "MM");
        String daily = DateFormatUtils.format(new Date(), "dd");

        // 打卡记录
        AttendPunchRecordDO onWorkRecord = new AttendPunchRecordDO();

        onWorkRecord.setId(UUID.randomUUID().toString().replace("-", ""));
        // 公司ID
        onWorkRecord.setCompanyId(plan.getCompanyId());
        // 公司名称
        onWorkRecord.setCompanyName(plan.getCompanyName());
        // 部门ID
        onWorkRecord.setDeptId("");
        // 部门名称
        onWorkRecord.setDeptName("");
        // 员工ID
        onWorkRecord.setEmpInfoId(staffVO.getEmpInfoId());
        // 员工姓名
        onWorkRecord.setEmpInfoName(staffVO.getEmpInfoName());
        // 考勤方案
        onWorkRecord.setAttendPlanId(plan.getId());
        // 考勤方案名称
        onWorkRecord.setAttendPlanName(plan.getName());
        // 年度
        onWorkRecord.setYear(yearly);
        // 月
        onWorkRecord.setMonth(monthly);
        // 日
        onWorkRecord.setDay(daily);
        // 打卡类型 ; 0-无效打卡,1-上班打卡,2-下班打卡
        onWorkRecord.setPunchType(1);
        // 标准时间
        onWorkRecord.setStandardTime(null);
        // 打卡时间(HH:mm)
        onWorkRecord.setPunchTime(null);
        // 打卡状态 ; 0-无效打卡,1-正常,2-迟到,3-早退
        onWorkRecord.setPunchStatus(0);
        // 迟到/早退分钟数
        onWorkRecord.setMinute(0);
        // 判定描述
        onWorkRecord.setDecisionDesc("");
        // 打卡坐标
        onWorkRecord.setCoordinate("");
        // 打卡地点
        onWorkRecord.setLocation("");
        // 打卡wifi
        onWorkRecord.setPunchWifi("");
        // 打卡来源 ; 1-app打卡,2-考勤机打卡
        onWorkRecord.setPunchSource(1);
        // 是否补卡 ; 1-是,0-否
        onWorkRecord.setIsMakeUp(false);
        onWorkRecord.setCreateUserId("");
        onWorkRecord.setGmtCreate(new Date());
        onWorkRecord.setModifiedUserId("");
        onWorkRecord.setGmtModified(new Date());
        onWorkRecord.setSiteId(plan.getSiteId());
        onWorkRecord.setValid(true);

        return onWorkRecord;
    }

    /**
     * 从打卡人员当中获取打卡人员
     *
     * @param attendPlanId
     * @param siteId
     */
    private Set<StaffVO> getStaffSetForPunchStaff(String attendPlanId, String siteId) {

        Set<StaffVO> staffIds = new HashSet<StaffVO>();

        // 查询考勤打卡参与人员
        AttendPunchStaffQuery attendPunchStaffQuery = new AttendPunchStaffQuery();
        attendPunchStaffQuery.setAttendPlanId(attendPlanId);
        List<AttendPunchStaffDO> staffList = attendPunchStaffService.selectDO(attendPunchStaffQuery, siteId);
        if (staffList != null && staffList.size() > 0) {
            for (AttendPunchStaffDO attendPunchStaff : staffList) {

                StaffVO staffVO = new StaffVO();
                staffVO.setEmpInfoId(attendPunchStaff.getEmpInfoId());
                staffVO.setEmpInfoName(attendPunchStaff.getEmpInfoName());
                staffIds.add(staffVO);
            }
        }

        return staffIds;
    }

    /**
     * 从考勤部门当中获取打卡人员
     *
     * @param attendPlanId
     * @param siteId
     * @return
     */
    private Set<StaffVO> getStaffSetForPunchDep(String attendPlanId, String siteId) {

        Set<StaffVO> staffIds = new HashSet<StaffVO>();

        // 查询考勤打卡参与部门
        AttendPunchDeptQuery attendPunchDeptQuery = new AttendPunchDeptQuery();
        attendPunchDeptQuery.setAttendPlanId(attendPlanId);
        List<AttendPunchDeptDO> deptList = attendPunchDeptService.selectDO(attendPunchDeptQuery, siteId);
        if (deptList != null && deptList.size() > 0) {
            for (AttendPunchDeptDO dept : deptList) {

                // 查询部门下的人员
                EmpDepQuery empDepQuery = new EmpDepQuery();
                empDepQuery.setDepId(dept.getDeptId());
                List<EmpDepDO> empDepList = empDepService.selectDO(empDepQuery, dept.getSiteId());
                if (empDepList.size() > 0) {
                    for (EmpDepDO empDep : empDepList) {

                        // 查询人员信息
                        EmpInfoDO empInfoDO = empInfoService.selectDOById(empDep.getEmpId(), empDep.getSiteId());
                        if (empInfoDO != null) {
                            StaffVO staffVO = new StaffVO();
                            staffVO.setEmpInfoId(empInfoDO.getId());
                            staffVO.setEmpInfoName(empInfoDO.getName());
                            staffIds.add(staffVO);
                        }
                    }
                }
            }
        }

        return staffIds;
    }

    /**
     *  考勤打卡日汇总
     *
     * @param plan
     * @return
     */
    private AttendPunchDailySummaryDO getAttendPunchDailySummaryDO(AttendPlanDO plan, Set<StaffVO> staffIds) {

        String yearly = DateFormatUtils.format(new Date(), "yyyy");
        String monthly = DateFormatUtils.format(new Date(), "MM");
        String daily = DateFormatUtils.format(new Date(), "dd");
        String dateStr = DateFormatUtils.format(new Date(), "yyyy-MM-dd");

        AttendPunchDailySummaryDO dailySummary = new AttendPunchDailySummaryDO();
        dailySummary.setId(UUID.randomUUID().toString().replace("-", ""));
        // 公司ID
        dailySummary.setCompanyId(plan.getCompanyId());
        // 公司名称
        dailySummary.setCompanyName(plan.getCompanyName());
        dailySummary.setAttendPlanId(plan.getId());
        dailySummary.setAttendPlanName(plan.getName());
        // 年
        dailySummary.setYearly(yearly);
        // 月
        dailySummary.setMonthly(monthly);
        // 日
        dailySummary.setDaily(daily);
        // 汇总日期
        try {
            dailySummary.setSummaryDate(DateUtils.parseDate(dateStr, "yyyy-MM-dd"));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 应出勤人数
        dailySummary.setShouldPeoples(staffIds.size());
        // 实际出勤人数
        dailySummary.setActualPeoples(0);
        // 迟到人数
        dailySummary.setLatePeoples(0);
        // 早退人数
        dailySummary.setEarlyPeoples(0);
        // 上班缺卡人数
        dailySummary.setOnWorkMissPeoples(0);
        // 下班缺卡人数
        dailySummary.setOffWorkMissPeoples(0);
        // 请假人数
        dailySummary.setLeavePeoples(0);
        dailySummary.setIsUsed(0);
        dailySummary.setCreateUserId("");
        dailySummary.setGmtCreate(new Date());
        dailySummary.setModifiedUserId("");
        dailySummary.setGmtModified(new Date());
        dailySummary.setSiteId(plan.getSiteId());
        dailySummary.setValid(true);

        return dailySummary;
    }

    /**
     * 初始化考勤打卡日报表
     *
     * @param summaryId
     * @param plan
     * @param staffVO
     * @return
     */
    public AttendPunchDailyReportDO getAttendPunchDailyReport(String summaryId, AttendPlanDO plan, StaffVO staffVO) {

        String yearly = DateFormatUtils.format(new Date(), "yyyy");
        String monthly = DateFormatUtils.format(new Date(), "MM");
        String daily = DateFormatUtils.format(new Date(), "dd");
        String dateStr = DateFormatUtils.format(new Date(), "yyyy-MM-dd");

        AttendPunchDailyReportDO dailyReport = new AttendPunchDailyReportDO();

        dailyReport.setId(UUID.randomUUID().toString().replace("-", ""));
        // 考勤打卡日汇总ID
        dailyReport.setDailySummaryId(summaryId);
        // 公司ID
        dailyReport.setCompanyId(plan.getCompanyId());
        // 公司名称
        dailyReport.setCompanyName(plan.getCompanyName());
        // 部门ID
        dailyReport.setDeptId("");
        // 部门名称
        dailyReport.setDeptName("");
        // 考勤规则ID
        dailyReport.setAttendPlanId(plan.getId());
        // 员工ID
        dailyReport.setEmpInfoId(staffVO.getEmpInfoId());
        // 员工姓名
        dailyReport.setEmpInfoName(staffVO.getEmpInfoName());
        // 年
        dailyReport.setYearly(yearly);
        // 月
        dailyReport.setMonthly(monthly);
        // 日
        dailyReport.setDaily(daily);
        // 签到地点
        dailyReport.setSignInLocation("");
        // 签退地点
        dailyReport.setSignOutLocation("");
        // 是否有外出 ; 1-是,0-否
        dailyReport.setIsGoOut(0);
        // 外出签到地点
        dailyReport.setGoOutLocation("");
        // 外出时长(小时)
        dailyReport.setGoOutHours(new BigDecimal("0"));
        // 打卡状态
        dailyReport.setAttendStatus(0);
        dailyReport.setIsUsed(0);
        dailyReport.setCreateUserId("");
        dailyReport.setGmtCreate(new Date());
        dailyReport.setModifiedUserId("");
        dailyReport.setGmtModified(new Date());
        dailyReport.setSiteId(plan.getSiteId());
        dailyReport.setValid(true);

        // 最早打卡时间
        dailyReport.setEarliestTime("");
        // 最晚打卡时间
        dailyReport.setLatestTime("");
        // 打卡次数
        dailyReport.setPunchCounts(0);
        // 工作时长(分钟)
        dailyReport.setWorkTimeMinute(0);
        // 历史考勤状态 (缺卡)
        dailyReport.setHisAttendStatus(0);
        // 加班状态;1-加班,0-未加班
        dailyReport.setOvertimeStatus(0);
        // 迟到或早退分钟数
        dailyReport.setMinutes(0);

        return dailyReport;
    }
}
